#pragma once

#include<iostream>
#include<string>
#include<sys/types.h>
#include<sys/socket.h>
#include<unistd.h>
#include<cstring>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<cstdlib>
#include<thread>
#include<stdio.h>

namespace zxf
{
    enum myerr{
        USAGE_ERR = 1,
        SOCKET_ERR,
        BIND_ERR,
        RECVFROM_ERR,
        SENDTO_ERR
    };


    class client
    {
    public:
        client( uint16_t port , std::string ip)//直接使用 0.0.0.0 即可
            :_port(port),_ip(ip)
        { }

        //初始化server
        void initserer()
        {
            _clientfd=socket(AF_INET, SOCK_DGRAM, 0);
            if(_clientfd == -1)
            {
                std::cout<<"socket error:"<<errno << strerror(errno) <<std::endl;
                exit(SOCKET_ERR);//socket创建失败
            }
            std::cout<<"socket success"<<std::endl;
            //客户端不需要显示的bind,因为不关心子第一次send的时候OS会自动bind一个合适的IP和PORT
        }



        //线程函数类内必须是静态的
        static void* func1(void* pfd)
        {
            //接受数据
            int sockfd = *(static_cast<int *>(pfd));
            pthread_detach(pthread_self());
            while (true)
            {
                char buffer[1024];
                struct sockaddr_in temp;
                socklen_t temp_len = sizeof(temp);
                size_t n = recvfrom(sockfd, buffer, sizeof(buffer) - 1, 0, (struct sockaddr *)&temp, &temp_len);
                if (n >= 0)
                    buffer[n] = 0;
                std::cout << buffer << std::endl;
            }

            return nullptr;
        }

        static void func2(int _clientfd)
        {
            while (true)
            {
                char buffer[1024];
                struct sockaddr_in temp;
                socklen_t temp_len = sizeof(temp);
                size_t n = recvfrom(_clientfd, buffer, sizeof(buffer) - 1, 0, (struct sockaddr *)&temp, &temp_len);
                if (n >= 0)
                    buffer[n] = 0;
                std::cout << buffer << std::endl;
            }
        }
        


        //启动服务器
        void runserver()
        {
            //服务器是一个死循环
            
            //创建一个线程
            //pthread_create(&_reader, nullptr, func1, (void *)&_clientfd);
            
            std::thread t1(func2 , _clientfd);

            for(;;)
            {
                struct sockaddr_in s_addr;
                bzero(&s_addr,sizeof(s_addr));
                s_addr.sin_family=AF_INET;
                s_addr.sin_port = htons(_port);
                s_addr.sin_addr.s_addr = inet_addr(_ip.c_str());
                //从标准输入读取书籍
                fprintf(stderr, "pleace input:");
                std::string message;
                std::getline(std::cin, message);//从cin流中行读取

                int t = sendto(_clientfd, message.c_str(), message.size(), 0, (struct sockaddr*)&s_addr, sizeof(s_addr));  
                if(t == -1)
                {
                    //std::cerr<<"sendto error:" <<errno <<strerror(errno)<<std::endl;
                    exit(SENDTO_ERR);
                }
            }

        }

        ~client()
        {
            close(_clientfd);//关闭socket
        }

    private:
        std::string _ip;//服务器的ip
        uint16_t _port; //服务器的端口号
        int _clientfd;//创建套接字需要的文件描述符

        pthread_t _reader;
    };

}//namespace zxf

